#include "addattentionsdialog.h"
#include "addattentionstask.h"
#include "captchaassisttask.h"
#include "disclaimerdialog.h"
#include "libs/base/service/downloader.h"
#include "libs/controls/loadingframe.h"
#include "libs/controls/toastlabel.h"
#include "libs/core/model/attentionmodel.h"
#include "libs/core/model/livemodel.h"
#include "libs/core/model/model.h"
#include "libs/core/model/modeltype.h"
#include "libs/core/model/presenter.h"
#include "liverecorder.h"
#include "liveviewmanager.h"
#include "services/yingceservice.h"
#include "ui_addattentionsdialog.h"
#include "usersettings.h"
#include "widgets/checkboxitemdelegate.h"
#include "yingce.h"
#include <QHeaderView>
#include <QMessageBox>
#include <QResizeEvent>
#include <QScrollBar>
#include <QStandardItemModel>
#include <QUrl>

AddAttentionsDialog::AddAttentionsDialog(LiveRecorder* recorder, QWidget* parent)
    : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint),
      ui(new Ui::AddAttentionsDialog),
      recorder_(recorder)
{
    ui->setupUi(this);
    ui->all_checkbox->setEnabled(false);
    ui->ok_button->setAutoDefault(false);
    ui->ok_button->setDefault(false);
    ui->ok_button->setEnabled(false);
    ui->cancel_button->setAutoDefault(false);
    ui->cancel_button->setDefault(false);

    // init platforms
    const auto& entries = YingCe::instance()->model()->liveModel()->webEntries();
    for (const auto& i : entries) {
        ui->platform_combobox->addItem(i.name, i.platform);
    }

    model_ = new QStandardItemModel(this);
    model_->setHorizontalHeaderLabels(QStringList { QString(), tr("Name"), tr("ID") });
    ui->table_view->setModel(model_);
    ui->table_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->table_view->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->table_view->setItemDelegateForColumn(CHECK_STATE_COLUMN, new CheckBoxItemDelegate(this));
    ui->table_view->setContextMenuPolicy(Qt::NoContextMenu);
    ui->table_view->setIconSize(QSize(32, 32));

    auto header = ui->table_view->horizontalHeader();
    header->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
    header->setSectionsClickable(false);
    header->setSectionsMovable(false);
    header->setSectionResizeMode(CHECK_STATE_COLUMN, QHeaderView::Fixed);
    header->setSectionResizeMode(NAME_COLUMN, QHeaderView::Stretch);
    header->setDefaultSectionSize(120);
    header->resizeSection(CHECK_STATE_COLUMN, 40);
    header->resizeSection(NAME_COLUMN, 200);
    header->resizeSection(ID_COLUMN, 200);

    header = ui->table_view->verticalHeader();
    header->hide();
    header->setDefaultSectionSize(36);

    connect(ui->ids_edit, &QLineEdit::textChanged, this, &AddAttentionsDialog::updateUiStatus);
    connect(ui->cancel_button, &QPushButton::clicked, this, &QDialog::reject);
    connect(ui->ok_button, &QPushButton::clicked, this, [this] {
        // 免责声明
        if (!UserSettings::instance().disclaimerAccepted()) {
            DisclaimerDialog dlg(true, this);
            if (dlg.exec() != QDialog::Accepted) {
                return;
            }

            UserSettings::instance().setDisclaimerAccepted(true);
            UserSettings::instance().save();
        }

        setUiEnabled(false);
        const int platform = ui->platform_combobox->currentData().toInt();
        if (platform == yc::KUAISHOW_PLATFORM_TYPE) {
            if (recorder_->liveViewManager()->infoPassedCaptcha()) {
                addAttentions();
            } else {
                const auto ret = QMessageBox::question(
                        this, tr("Captcha Assist"),
                        tr("To ensure the security of your visit, a slider verification needs to "
                           "be completed. After clicking 'Ok', the Kuaishou verification page will "
                           "automatically open. You just need to drag the slider to complete the "
                           "verification. There is no need to log in to your account. Thank you "
                           "for your cooperation!"),
                        QMessageBox::Ok | QMessageBox::Close, QMessageBox::Ok);
                if (ret == QMessageBox::Ok) {
                    auto t = new CaptchaAssistTask(recorder_, this);
                    connect(t, &CaptchaAssistTask::finished, this,
                            &AddAttentionsDialog::addAttentions);
                    connect(t, &CaptchaAssistTask::finished, this,
                            &AddAttentionsDialog::addAttentions);
                    t->start();
                } else {
                    setUiEnabled(true);
                }
            }
        } else {
            addAttentions();
        }
    });

    connect(ui->keyword_edit, &QLineEdit::editingFinished, this,
            &AddAttentionsDialog::searchPresenters);
    connect(ui->table_view->verticalScrollBar(), &QScrollBar::valueChanged, this,
            [this](int value) {
                if (value >= ui->table_view->verticalScrollBar()->maximum() - 10) {
                    searchMore();
                }
            });

    connect(model_, &QStandardItemModel::itemChanged, this, [this](QStandardItem* item) {
        if (item->column() == CHECK_STATE_COLUMN) {
            updateAllCheckState();
            updateUiStatus();
        }
    });
    connect(ui->all_checkbox, &QCheckBox::clicked, this, [this](bool checked) {
        const int count = model_->rowCount();
        for (int i = 0; i < count; ++i) {
            auto item = model_->item(i, CHECK_STATE_COLUMN);
            if (item->isEnabled()) {
                item->setData(checked ? Qt::Checked : Qt::Unchecked, DataRole::CHECK_STATE_ROLE);
            }
        }
        updateUiStatus();
    });
}

AddAttentionsDialog::~AddAttentionsDialog()
{
    delete ui;
}

QStringList AddAttentionsDialog::getIds() const
{
    QStringList ids;
    const QString s = ui->ids_edit->text().trimmed();
    if (s.isEmpty()) {
        int count = model_->rowCount();
        for (int i = 0; i < count; ++i) {
            auto item = model_->item(i, CHECK_STATE_COLUMN);
            if (item->data(DataRole::CHECK_STATE_ROLE).toInt() == Qt::Checked) {
                const auto t = model_->item(i, ID_COLUMN)->text();
                ids.push_back(t);
            }
        }
    } else {
        // 兼容中文逗号（，）
        const QString sep { "\357\274\214" };
        if (s.contains(sep)) {
            ids = s.split(sep, Qt::SkipEmptyParts);
        } else {
            ids = s.split(',', Qt::SkipEmptyParts);
        }
    }
    return ids;
}

void AddAttentionsDialog::searchPresenters()
{
    const QString keyword = ui->keyword_edit->text().trimmed();
    if (keyword_ == keyword) {
        return;
    }

    model_->setRowCount(0);
    ui->all_checkbox->setCheckState(Qt::Unchecked);
    ui->all_checkbox->setEnabled(false);
    keyword_ = keyword;

    if (!keyword.isEmpty()) {
        const int platform = ui->platform_combobox->currentData().toInt();
        YingCeService::instance()->searchPresenters(
                platform, keyword, 0,
                yc::ResponseHandler(
                        this, [this](const yc::Request& request, const yc::Response& response) {
                            Q_UNUSED(request)
                            if (response.status() == yc::OK_CODE) {
                                const QJsonObject jo = response.data().toObject();
                                int count = jo["count"].toInt();
                                if (count > 0) {
                                    const QJsonArray ja = jo["presenters"].toArray();
                                    for (const auto& i : ja) {
                                        addItem(yc::Presenter { i.toObject() });
                                    }
                                    // 全选可用
                                    ui->all_checkbox->setEnabled(true);
                                }
                                search_count_ = count;
                            }
                        }));
    }
}

void AddAttentionsDialog::searchMore()
{
    const int count = model_->rowCount();
    if (search_count_ > count) {
        const int platform = ui->platform_combobox->currentData().toInt();
        YingCeService::instance()->searchPresenters(
                platform, keyword_, count,
                yc::ResponseHandler(
                        this, [this](const yc::Request& request, const yc::Response& response) {
                            Q_UNUSED(request)
                            if (response.status() == yc::OK_CODE) {
                                const QJsonObject jo = response.data().toObject();
                                int count = jo["count"].toInt();
                                if (count > 0) {
                                    const QJsonArray ja = jo["presenters"].toArray();
                                    for (const auto& i : ja) {
                                        addItem(yc::Presenter { i.toObject() });
                                    }
                                    // 全选可用
                                    ui->all_checkbox->setEnabled(true);
                                }
                            }
                        }));
    }
}

void AddAttentionsDialog::addItem(const yc::Presenter& presenter)
{
    auto am = YingCe::instance()->model()->attentionModel();
    if (am->find(presenter.id) != nullptr)
        return;

    const Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    const int row = model_->rowCount();
    const QString filename = QUrl { presenter.avatar }.fileName();

    auto item = new QStandardItem;
    item->setFlags(flags);
    item->setData(Qt::Unchecked, DataRole::CHECK_STATE_ROLE);
    model_->appendRow(item);

    auto name_item = new QStandardItem(presenter.nickname);
    name_item->setFlags(flags);
    name_item->setData(filename, AVATAR_ROLE);
    model_->setItem(row, NAME_COLUMN, name_item);

    item = new QStandardItem(presenter.platform_id);
    item->setFlags(flags);
    model_->setItem(row, ID_COLUMN, item);

    if (!presenter.avatar.isEmpty()) {
        const auto res_dir = UserSettings::instance().resDir();
        const auto filename = QUrl { presenter.avatar }.fileName();
        if (QFileInfo::exists(res_dir.absoluteFilePath(filename))) {
            name_item->setIcon(QIcon(res_dir.absoluteFilePath(filename)));
        } else {
            downloadAvatar(presenter.avatar);
        }
    }
}

void AddAttentionsDialog::downloadAvatar(const QString& url)
{
    const yc::DownloadResource res { url, QUrl { url }.fileName() };
    if (!downloader_) {
        downloader_ = new yc::Downloader(YingCeService::instance(), QString(),
                                         UserSettings::instance().resDir(), false, 0, this);
        connect(downloader_, &yc::Downloader::downloaded, this, [this](const QString& filename) {
            QString avatar_name;
            int count = model_->rowCount();
            for (int i = 0; i < count; ++i) {
                avatar_name = model_->data(model_->index(i, NAME_COLUMN), AVATAR_ROLE).toString();
                if (filename.endsWith(avatar_name, Qt::CaseInsensitive)) {
                    model_->item(i, NAME_COLUMN)->setIcon(QIcon(filename));
                }
            }
        });
        downloader_->start();
    }
    downloader_->addResource(res);
}

bool AddAttentionsDialog::canAdd() const
{
    bool ok = false;
    const QString ids = ui->ids_edit->text().trimmed();
    if (ids.isEmpty()) {
        int count = model_->rowCount();
        for (int i = 0; i < count; ++i) {
            if (model_->item(i, CHECK_STATE_COLUMN)->data(DataRole::CHECK_STATE_ROLE).toInt()
                == Qt::Checked) {
                ok = true;
                break;
            }
        }
    } else {
        ok = true;
    }
    return ok;
}

void AddAttentionsDialog::updateUiStatus()
{
    ui->ok_button->setEnabled(canAdd());
}

void AddAttentionsDialog::setUiEnabled(bool enabled)
{
    ui->platform_combobox->setEnabled(enabled);
    ui->ok_button->setEnabled(enabled);
    ui->ids_edit->setEnabled(enabled);
    ui->keyword_edit->setEnabled(enabled);
    ui->table_view->setEnabled(enabled);
    ui->all_checkbox->setEnabled(enabled);
}

void AddAttentionsDialog::updateAllCheckState()
{
    int checked_count = 0;
    const int count = model_->rowCount();
    for (int i = 0; i < count; ++i) {
        auto item = model_->item(i, CHECK_STATE_COLUMN);
        if (item->data(DataRole::CHECK_STATE_ROLE).toInt() == Qt::Checked) {
            checked_count++;
        }
    }
    if (checked_count == count) {
        ui->all_checkbox->setCheckState(Qt::Checked);
    } else if (checked_count == 0) {
        ui->all_checkbox->setCheckState(Qt::Unchecked);
    } else {
        ui->all_checkbox->setCheckState(Qt::PartiallyChecked);
    }
}

void AddAttentionsDialog::showLoading()
{
    if (!loading_frame_) {
        loading_frame_ = new yc::LoadingFrame(tr("Please wait while adding"), this);
    }
    const auto sz = size();
    loading_frame_->resize(sz.width(), sz.height() - 40);
    loading_frame_->show();
    loading_frame_->raise();
}

void AddAttentionsDialog::hideLoading()
{
    if (loading_frame_) {
        loading_frame_->hide();
    }
}

void AddAttentionsDialog::addAttentions()
{
    const int platform = ui->platform_combobox->currentData().toInt();
    const QStringList ids = getIds();
    auto t = new AddAttentionsTask(recorder_, platform, ids, this);
    connect(t, &AddAttentionsTask::aboutToStart, this, &AddAttentionsDialog::showLoading);
    connect(t, &AddAttentionsTask::finished, this, &QDialog::accept);
    connect(t, &AddAttentionsTask::failed, this, [this](int error, const QString& message) {
        Q_UNUSED(error)
        hideLoading();
        setUiEnabled(true);
        yc::ToastLabel::showMessage(tr("Failed to add a follow presenter, error:") + message, this,
                                    5000);
    });
    t->start();
}
